/**
 * Copyright (C) 2005 WUZEWEN. All rights reserved.
 * WUZEWEN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package com.kingcore.director.setting.bean;


import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import org.apache.log4j.Logger;

import wzw.util.FileUtils;

import com.kingcore.director.DirectorConstants;
import com.kingcore.framework.context.ApplicationContext;

/** 
 * <p>计算级系统资料备份程序。用于文件复制。
 * 		Zeven Modify on 2007-04-26, 按照功能高内聚，低耦合，更多适合重用。</p>
 * @author	WUZEWEN on 2005-10-16
 * @version	1.0
 * @see		Object#equals(java.lang.Object)
 * @see		Object#hashCode()
 * @see		HashMap
 * @since	JDK5
 */

public class FilesCopyBean  implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	/* 日志记录i对象 */
	public static Logger log=Logger.getLogger(FilesCopyBean.class);
	
	//备份方法：在指定的时间间隔做完全备份，其他时间做增量备份
	public static int FILEBACKUPTYPE_FULL=1;	//1：完全备份
	public static int FILEBACKUPTYPE_INCREASE=2;//2：增量备份，包括增加的文件、文件夹
	private static String FilePath="";
	private int backupType=2;					//备份类型，默认为2
	private String lastBackup="";				//上次备份总路径
	private StringBuffer error_msg= new StringBuffer();			//错误信息，可以抛出
	
	SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");	//类公用的日期格式对象。去掉 :ss
	private String[] filterFileExtensions;	// filename extension 保留不需要复制的文件扩展名数组。 对于一次复制任务相同。一次复制任务可以对应多个目录。
	private String[] filterFolders;		// 保留不需要复制的文件夹数组。

	/**
	 * Method FilesCopyBean
	 *
	 *
	 */
	public FilesCopyBean() {
	}
		
	/**
	 * Method main
	 *
	 *
	 * @param args 运行参数 0:复制的分类; 1:复制类型; 2:复制目标;
	 *
	 */
	public static void main(String[] args) throws Exception {
		// test FilesCopyBean
		FilesCopyBean fcb = new FilesCopyBean();
		fcb.executeCopy( args );
	}
	
	protected void executeCopy(List fromList, String toFolder, String lastFolder )  throws Exception {
		executeCopy( fromList, toFolder, lastFolder, "ZX" );
	}

	
	/**
	 *  这个是文件夹复制类的入口，是纯粹文件复制功能的开始！  实现了文件复制带路径的规范，所以对于其他的地方使用还是有一定的局限性。
	 *  
	 * if lastFolder is null then full copy. 这里的复制一定是带有以前的路径文件夹的。
	 * @param fromList 要复制的文件/文件夹集合
	 * @param toFolder 目标文件夹
	 * @param lastFolder 上次复制的对比的文件夹，如果为null 表示全复制；如果==toFolder 表示追加复制；其他值表示差量复制。
	 * @param ts_fzfx 复制的方向；  FX 表示是反向复制；
	 * @throws Exception
	 */
	protected void executeCopy(List fromList, String toFolder, String lastFolder, String ts_fzfx )  throws Exception {
		
		String copyFrom=null;
		File tempFile=null;
		boolean isFile=false;
		String diskNeeded="true";
		String thisCopyTo, thisLastBackup;
		int beginPos=0;

		try{
			for(int i=0; i<fromList.size(); i++){

//					copyFrom=fb.toGB2312(copyFrom);		//中文乱码问题
//					copyTo  =fb.toGB2312(copyTo);	
//					lastBackup=fb.toGB2312(lastBackup);
				
				copyFrom = fromList.get(i).toString();
				//by wzw:保持windows的路径风格‘\’连接  keep as same as File.separator
//				copyFrom=copyFrom.replace("\\","/");	//替换路径分隔符  eg:   E:/Woo_Java/apps_src/
//				toFolder  =toFolder.replace("\\","/");				// eg:   F:/				
//				if(lastFolder!=null){
//					lastFolder=lastFolder.replace("\\","/");		// eg:   F:/
//				}
				
				//log.debug( "copyFrom---" + copyFrom );
				// 是否是文件
				tempFile = new File(copyFrom);
				isFile = false;
				if(tempFile!=null && tempFile.isFile() ){
					isFile = true;
				}
				
				if( !copyFrom.endsWith(File.separator) && !isFile){		//保证以/结尾
					copyFrom += File.separator;      // by wzw on 2007-03-21
				}
					
				//eg:lastBackup="E:/Woo_backup/2005-11-16_C/"			C:D:E:F   
				log.debug("copy-from "+copyFrom +" to "+toFolder+" last "+lastFolder);
				if( !isFile && diskNeeded!=null && diskNeeded.trim().equals("false")){	// 不需要盘符的情况，以后可以修改为不需要盘符和文件夹
					thisCopyTo = toFolder + copyFrom.substring(beginPos).replace(":","");
					thisLastBackup= lastFolder + copyFrom.substring(beginPos).replace(":","");
				}else{
					thisCopyTo = toFolder + copyFrom.replace(":","");		// 目标文件夹补充带有盘符
					thisLastBackup= lastFolder + copyFrom.replace(":","");
				}
				
				// 分为反先复制和正向复制，如 由硬盘到移动盘 <--> 有移动盘到硬盘
				if(ts_fzfx.equals("FX")){	// 反向复制还原
					log.debug("copy-from "+thisCopyTo +" to "+copyFrom+" last "+copyFrom);					
					if( !(new File(thisCopyTo)).exists() ){
						error_msg.append( "\n"+ thisCopyTo + " 不存在!");
						continue;
					}
					this.copyFileOrFolder(thisCopyTo,
										 copyFrom,
										 copyFrom,
										 true );		//比较文件是否存在？
				} else {					// 默认为顺向复制
					log.debug("copy-from "+copyFrom +" to "+ thisCopyTo +" last "+thisLastBackup);
					//log.debug("======copy-from "+copyFrom +" to "+copyTo+" last "+thisLastBackup);
					
					if( !(new File(copyFrom)).exists() ){
						error_msg.append(  "\n"+ copyFrom + " 不存在!");
						continue;
					}
					this.copyFileOrFolder(copyFrom,
										 thisCopyTo,
										 thisLastBackup,
										 true );		//比较文件是否存在？
				}
			}
		}catch(Exception e){
			log.error("编码转换出现错误！");
			System.exit(0);
		}
	}

	/**
	 * one access do copy .   接收传递的参数，得到目标路径；同时需要取数据库，生成要复制的文件集合。
	 * @param args
	 * @throws Exception
	 */
	protected void executeCopy(String[] args)  throws Exception {

		sdf.applyPattern("yyyy-MM-dd");
		
		Date toDay=new Date();
		String strDate=sdf.format(toDay);

		//获取配置文件值
		//java.util.Properties pro=new java.util.Properties();
		String conf_prefix=null;
		String destPath=null;
		String strInterval=null;
		String strPos=null;
		int beginPos;
		
		int interval;
		String lastBackup="";
		String copyType="";		//复制类型： 1:硬盘to硬盘;2硬盘to移动盘;3:移动盘to硬盘;
		String destBackup="";	//指定的备份目标路径，而不是按照日期生成yyyy-mm-dd_I。

		String sql="";
		Connection conn=null;
		Statement stmt=null;
		ResultSet rs=null;

		try
		{
			conn= ApplicationContext.getInstance().getDataSourceManager().getConnection();
			stmt = conn.createStatement();
			
			conf_prefix = args[0];	// 复制分类，类别如 A1, A2 ...
			copyType = args[1];		// 复制类型，如 硬盘到移动盘，硬盘到硬盘 ...
			destPath = args[2];		// 复制目标地址
			lastBackup = destPath;	//上次全备路径
			destBackup = destPath;	//本次路径
			
			// copy(fromlist, toFolder, lastFolder );

			log.debug ("user-config="+conf_prefix);
			log.debug ("user-copyType="+copyType);
			log.debug ("user-destPath="+destPath);
			log.debug ("user-strInterval="+strInterval);

			// 根据复制类型，确定复制路径是否需要盘符。
			if(copyType.equals("3")){
				strPos="5";
			} else {
				strPos="0";
			}

			
			beginPos=0;
			if(strPos!=null){
				beginPos   =Integer.parseInt(strPos);	//生成目标路径开始位置
			}
						
			if(strInterval!=null){
				interval=Integer.parseInt(strInterval);
			}else {
				interval=0;
			}
			
			String copyFrom="";	//"D:/test/";		//backup 源文件夹，必须要后面的/。
			String copyTo=destPath.trim();		//"F:/Woo_backup/";	//backup 目标文件夹
			
			
			//log.debug ("to"+copyTo);
			//FilesCopyBean fb=new FilesCopyBean();
			//调用方法  //if(toDay.getDay()==1){
			this.backupType = FilesCopyBean.FILEBACKUPTYPE_FULL;
			
			//下面是自定义完全备份间隔的代码
			//如果配置信息没有指定上次全备份路径，循环查找上次全备份
			long lTime= toDay.getTime() ;//+ ( new Float(Float.parseFloat(tjsd)*60*60) ).intValue() ;	
			Date pMonday=new Date();
			if(lastBackup==null||lastBackup.trim().equals("")){
				for(int i=1;i<interval;i++){
					pMonday.setTime(lTime - (i)*24*60*60*1000);
					String strMonday=sdf.format(pMonday);				
					
					this.lastBackup=copyTo+strMonday+"_C/";//+copyFrom.replace(":","");
					lastBackup=this.lastBackup;
					if(new File(this.lastBackup).exists()){
						log.debug("increase");
						this.backupType=FilesCopyBean.FILEBACKUPTYPE_INCREASE;
						log.debug("pday complete is "+strMonday);
						break;
					}
				}
			}else{
				this.backupType=FilesCopyBean.FILEBACKUPTYPE_INCREASE;
			}	
			
	
			log.debug("bktype="+(this.backupType==1?"完全备份":"增量备份"));			
			
			//备份目标文件夹
			if(destBackup==null||destBackup.trim().equals("")){
				if(this.backupType==FilesCopyBean.FILEBACKUPTYPE_FULL){
					copyTo+=strDate+"_C/";//+copyFrom.replace(":","");
				}else{
					copyTo+=strDate+"_I/";//+copyFrom.replace(":","");
				}
			}else{
				copyTo=destBackup;
			}
			
			// 设置过滤信息。
			this.setFilter();
			
			String ts_fzfx = args[3];	//复制的方向
			String ts_paths = args[4];	//只复制某一条
			if( ts_paths==null ){
				sql = "Select Path From "+DirectorConstants.FMT_FileCopy+" Where USEFUL='Y' AND LBBH='"+conf_prefix+"' Order By Path ASC";
			
			} else {
				sql = "Select Path From "+DirectorConstants.FMT_FileCopy+" Where Path in ("+ts_paths+") AND LBBH='"+conf_prefix+"' Order By Path ASC";
			
			}
			
			log.debug("sql = "+ sql);
			rs = stmt.executeQuery(sql);
			
			// 获取要复制的目录/文件集合
			List fromList = new ArrayList();
			while(rs.next()){

				copyFrom= rs.getString("Path");
				//copyFrom=pro.getProperty(conf_prefix+"srcPath"+i);
				if(copyFrom==null||copyFrom.trim().equals("")){
					continue;
				} else {
					copyFrom = copyFrom.trim();
					fromList.add( copyFrom ); // add
				}
				log.debug("copyFrom="+copyFrom);				
			}
			this.executeCopy( fromList, copyTo, lastBackup, ts_fzfx ) ;			// 提交要复制的文件夹集合进行复制操作。
			
			if( error_msg.toString().trim().equals("")){
				log.info("copy files success!");
			
			}else{
				log.info("copy files finish with error:" + error_msg );
				throw new Exception( error_msg.toString() );  //throw execute file copy Exception.
			}
			
		}catch(SQLException e){
			log.error ("Database Error: " +e.getMessage());
			//return ;
			throw e ;
		} catch(Exception e){
			throw e ;
		} finally{
			//释放资源
			try {
				if(rs!=null){
					rs.close();
				}
				if(stmt!=null){
					stmt.close();
				}
				if(conn!=null){
					conn.close();
				}
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		}		
	}

	/**
	 * 设置复制的过滤信息。
	 * @throws Exception
	 */
	protected void setFilter() throws Exception{

		String sql="";
		Connection conn=null;
		Statement stmt=null;
		ResultSet rs=null;
		try
		{
			conn= ApplicationContext.getInstance().getDataSourceManager().getConnection();
			stmt = conn.createStatement();

			// 获取不需要复制的文件和文件夹信息集合
			// 不需要复制的文件扩展名集合
			sql =  "SELECT VAL FROM "+DirectorConstants.SYS_Setting +
			               " Where KEY='"+DirectorConstants.File_Copy_Not_Include_File_Extends+"'" ;
			rs=stmt.executeQuery(sql);
			String str_temp = "";
			if (rs.next()) {
				str_temp = rs.getString("VAL");
				if( str_temp!=null){
					//log.debug("----filterFolders-- 0 1 2  " + str_temp);
					filterFileExtensions = str_temp.split(",") ;

					// test, and give infor to console.
					str_temp = "";
					for( int ti=0; ti<filterFileExtensions.length; ti++){
						str_temp += filterFileExtensions[ti]+" ";
					}
					log.info("not need copy files is: " + str_temp );
					//log.debug("----filterFolders-- 0 1 3  " + filterFileExtensions);
					//log.debug("----------2 " + filterFileExtensions.length);
				}
				
			}
			this.setFilterFileExtensions( filterFileExtensions );		// 设置过滤得文件扩展名

			// 不需要复制的文件夹名集合
			sql =  "SELECT VAL FROM "+DirectorConstants.SYS_Setting +
					" Where KEY='"+DirectorConstants.File_Copy_Not_Include_Folders+"'" ;
			rs=stmt.executeQuery(sql);
			if (rs.next()) {
				str_temp = rs.getString("VAL");
				if( str_temp!=null){
					filterFolders = str_temp.split(",") ;
						
					// test, and give infor to console.
					str_temp = "";
					for( int ti=0; ti<filterFolders.length; ti++){
						str_temp += filterFolders[ti]+" ";
					}
					log.info("not need copy filterFolders is: " + str_temp );
				}
			}
			this.setFilterFolders( filterFolders );				// 设置要过滤的文件夹
			
		}catch(SQLException e){
			log.error ("Database Error: " +e.getMessage());
			//return ;
			throw e ;
		} catch(Exception e){
			throw e ;
		} finally{
			//释放资源
			try {
				if(rs!=null){
					rs.close();
				}
				if(stmt!=null){
					stmt.close();
				}
				if(conn!=null){
					conn.close();
				}
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		}	
	}
	
	
	protected boolean copyFileOrFolder(String copyFrom,String copyTo,String lastBackup ) throws Exception{
		return copyFileOrFolder( copyFrom, copyTo, lastBackup, true );
	}

	/**
     * <p>复制某一文件夹/文件到指定的文件夹/文件，采用字节流复制。 完全与数据库、规范(可以设置文件夹/扩展名过滤规范)无关的复制方法。 
     * 		文件/文件夹在这里做统一的处理。</p>
     * @author WUZEWEN on 2005-10-17
     * @param copyFrom 原文件夹
     * @param copyTo 目标文件夹
     * @param needCompare 是否有文件需要比较，尚未启用，减少复制时间
     * @return 复制成功返回true，复制失败返回false。
     * @throws no exception
     */
	protected boolean copyFileOrFolder(String copyFrom,String copyTo,String lastBackup, boolean needCompare) throws Exception{
		File fileFromFolder=new File(copyFrom);
		File fileToFolder=new File(copyTo);
		File lastBackFolder=new File(lastBackup);

		boolean gotoNext = false;
		
		try{
			
			// Zeven add deploy file on 2007-03-21.
			// if fileFromFolder is not null and is a file but not a folder, copy the file, then retrun.
			if(fileFromFolder!=null && fileFromFolder.isFile() ){
				//fileToFolder = new File( copyTo + fileFromFolder.getName() );
				return copySingleFile( fileFromFolder, fileToFolder, lastBackFolder );
			}
			
			// Zeven on 2007-05, for temp folder. 创建文件夹(包括temp_打头的)，如果以temp_打头， 对于temp_* 文件夹，无论是内部递归还是外部指定，统一不复制下面的文件。
			// if is a folder and startWith( temp_ ), if folder not exists, create it, then return.
			if( FileUtils.isTempFolder(fileFromFolder) ){
				if( ( this.backupType==FilesCopyBean.FILEBACKUPTYPE_FULL && !(new File( copyTo )).exists() ) || 
					( this.backupType==FilesCopyBean.FILEBACKUPTYPE_INCREASE && !(new File( lastBackup )).exists() )
				  ){

					//log.debug( "mkdir-2--"+copyTo+fileName+"/" );
					(new File( copyTo )).mkdirs();
					(new File( copyTo )).setLastModified( (new File(copyFrom+"/")).lastModified() );
					//System.exit(0);  文件夹下的文件修改之后，文件夹的lastModified() 被操作系统自动修改，这点不是程序导致的。 Zeven
				}
				return true;		// 文件夹处理之后直接返回
			}
	
			// if is a folder and have been seting not dealing
			// temp* -- 临时文件夹(内置)； CVS -- CVS管理工具文件夹；
			// if folder is a undealing folder, create it if not exists, then return.
			//  对于内部递归循环，一定不处理设置的特定文件夹！！！ 但是这里是对于第一次进入文件夹复制，而不是内部递归，还是不过滤？？？
			/*
			gotoNext = false;
			for( int fi=0; fi<filterFolders.length; fi++){
				//log.debug( fileName+ "----filterFolders-- "+ filterFolders[fi] + fileName.equals( filterFolders[fi]) );
				if( fileFromFolder.getName().equals( filterFolders[fi] ) ){
					gotoNext = true;
					break;		// not continue;
				}
			}
			if( gotoNext ){
				if(!(new File( copyTo )).exists()){
					//log.debug( "mkdir-2--"+copyTo+fileName+"/" );
					(new File( copyTo )).mkdirs();
					(new File( copyTo )).setLastModified( (new File(copyFrom+"/")).lastModified() );
					//System.exit(0);  文件夹下的文件修改之后，文件夹的lastModified() 被操作系统自动修改，这点不是程序导致的。 Zeven
				}
				return true;		// 直接返回
			} */

			// get all files under current folder, loop them.
			File[] files=fileFromFolder.listFiles();
			//先创建对象(引用)
			String fileName="";
			File toFile=null;
			File lastFile=null;
	
			sdf.applyPattern( "yyyy-MM-dd HH:mm" );
			
			//如果是完全备份而且目标文件夹不存在则创建，否则只有有文件复制时才复制相应的文件夹。
			if( ( this.backupType==FilesCopyBean.FILEBACKUPTYPE_FULL && !fileToFolder.exists() ) ||
				( this.backupType==FilesCopyBean.FILEBACKUPTYPE_INCREASE && !lastBackFolder.exists() )
			  ){
				
				fileToFolder.mkdirs();
				//log.debug( "mkdir-1--"+fileToFolder.getPath() );
				fileToFolder.setLastModified(fileFromFolder.lastModified());//同步时间
			}
			
			// loop files.
			for(int i=0;i<files.length;i++){
				fileName=files[i].getName();	//初始化对象
				if(files[i].isFile()){			// is file, not folder.
					toFile=new File(copyTo+fileName);
					lastFile=new File(lastBackup+fileName);
					
					// 有些文件不复制, Zeven on 2007-04-18
					// .class -- java 编译文件； .temp -- 临时文件；
					gotoNext = false;
					for( int fi=0; fi<filterFileExtensions.length; fi++){
						//log.debug("---filterFileExtensions--- "+ filterFileExtensions[fi]);
						if( fileName.endsWith( filterFileExtensions[fi] ) ){
							gotoNext = true;
							break;			// not continue
						}
					}
					if( gotoNext ){
						continue;
					}

					//如果文件没有改变，退出
					//log.debug ("file= "+fileName+"\n"+toFile.lastModified()+"=="+files[i].lastModified()+"\n"+new Date(toFile.lastModified())+"\n"+new Date(files[i].lastModified()));
					//log.debug (sdf.format(new Date(toFile.lastModified())) +" "+ sdf.format(new Date(files[i].lastModified())));
					//log.debug (sdf.format(new Date(toFile.lastModified())).equals(sdf.format(new Date(files[i].lastModified()))));
					if(this.backupType==FilesCopyBean.FILEBACKUPTYPE_INCREASE){
						if(needCompare && sdf.format(new Date(lastFile.lastModified())).compareTo(sdf.format(new Date(files[i].lastModified()))) >=0){
							//如果上次备份的文件大于等于现在的工作文件，不处理
							//log.debug ("file not modified!");
						}else{

							//log.info ("file modified and copy-["+sdf.format(new Date(files[i].lastModified()))+"|"+sdf.format(new Date(lastFile.lastModified()))+"]:"+copyTo+fileName);							
							copySingleFile( files[i], toFile, toFile );  // null	
						}
						
					}else{			
		
						//完全备份
						copySingleFile( files[i], toFile, toFile );	//null

					}
					
				}else if(files[i].isDirectory()){		// 文件夹处理
					//log.debug ("file= "+fileName);
					//对于临时文件夹(名称以temp打头的)以及其子文件夹不备份。
					//////if((!fileName.toLowerCase().equals("temp")) && (!fileName.toLowerCase().equals("temporary"))){
					
					//创建文件夹：全复制一定创建；增量复制如果是新增的也创建；
					if( ( this.backupType==FilesCopyBean.FILEBACKUPTYPE_FULL && !(new File(copyTo+fileName+"/")).exists() ) ||
						( this.backupType==FilesCopyBean.FILEBACKUPTYPE_INCREASE && !(new File(lastBackup+fileName+"/")).exists() )
					  ){

						//log.debug( "mkdir-2--"+copyTo+fileName+"/" );
						(new File(copyTo+fileName+"/")).mkdirs();
						(new File(copyTo+fileName+"/")).setLastModified( (new File(copyFrom+fileName+"/")).lastModified() );
						//System.exit(0);  文件夹下的文件修改之后，文件夹的lastModified() 被操作系统自动修改，这点不是程序导致的。 Zeven
					}
					
					// 如果是不处理的文件夹，循环下一条。 不处理的文件夹： 
					//temp* -- 临时文件夹(内置)； CVS -- CVS管理工具文件夹；  对于内部递归循环，一定不处理设置的特定文件夹。
					gotoNext = false;
					if( FileUtils.isTempFolder(fileName) ){
						continue;
						
					}else{
						for( int fi=0; fi<filterFolders.length; fi++){
							//log.debug( fileName+ "----filterFolders-- "+ filterFolders[fi] + fileName.equals( filterFolders[fi]) );
							if( fileName.equals( filterFolders[fi] ) ){
								gotoNext = true;
								break;		// not continue;
							}
						}
						// 跳出第一层循环，继续上一层循环。
						if( gotoNext ){
							continue;
						}
					}
					
					// 递归子文件夹
					copyFileOrFolder(copyFrom+fileName+"/",copyTo+fileName+"/",lastBackup+fileName+"/", (new java.io.File(lastBackup+fileName+"/")).exists() );
				}
			}

		}catch(Exception ex){
			//log.error ("ex="+ex);
			//throw new Exception("复制"+copyFrom+"失败！\n"+ex);
			error_msg.append( "\n"+ "复制"+copyFrom+"失败！" );	//记录错误信息
		}
		return true;
	}
	
	/**
	 * <p>copy single file.  wzw: core function.
	 *  复制单个文件，判断目的文件是否存在。 
	 *  如果存在判断文件是否被修改，如果没有修改不复制，如果修改了，则先删除目的文件，再创建新文件并复制，
	 *  先删除再复制的原因是为了解决Windows系统中的文件名称大小写不敏感问题。</p>
	 *  
	 * @param fromFile 待复制的文件
	 * @param toFile 目标文件
	 * @param lastFile 上次的参考文件
	 * @return
	 * @throws Exception
	 */
	protected boolean copySingleFile(File fromFile , File toFile , File lastFile) throws Exception{

		FileOutputStream fout=null;
		BufferedInputStream bufferIn=null;
		byte[] databytes=new byte[2048];
		int k;
		long lst;

		sdf.applyPattern( "yyyy-MM-dd HH:mm" );
		
		if( toFile!=null && lastFile !=null 
				&& sdf.format(new Date(lastFile.lastModified())).compareTo(sdf.format(new Date( fromFile.lastModified()))) >=0){
			//如果上次备份的文件大于等于现在的工作文件，不处理
			//log.debug ("file not modified!")o;
			

			///log.debug( org.apache.commons.io.FilenameUtils.);
//			log.debug( org.apache.commons.io.FilenameUtils.getBaseName(toFile.getAbsolutePath() ) );
//			log.debug("-----------rename"+toFile.getName() + "\n"+fromFile.getName());
//			if(!fromFile.getName().equals( toFile.getName() )){
//				log.debug("-----------rename"+toFile.getName() + "\n"+fromFile.getName());
//				toFile.renameTo( fromFile );	//修改名称，主要是针对大小写问题--- 不能解决windows系统文件名称大小写不敏感问题。
//			}
			
			return true;
		}else{
			//log.debug ("---------------2--" + toFile.getParent());
			// log.info ("file modified and copy-["+sdf.format(new Date( fromFile.lastModified()))+"|"+sdf.format(new Date(lastFile.lastModified()))+"]:" + toFile.getAbsolutePath() );
			
			log.info ("file modified and copy-["+sdf.format(new Date(fromFile.lastModified()))+"|"
					+ (lastFile.exists()?sdf.format(new Date(lastFile.lastModified())):"no old file found")
					+"]: " + fromFile.getAbsolutePath());
													
			// 文件夹处理，有文件复制了，一定要先创建文件夹，无论是完全备份还是增量备份!
			File toFolder = new File( toFile.getParent() );
			if( !toFolder.exists() ){

				//log.debug( "mkdir-3--"+toFile.getParent() );
				toFolder.mkdirs() ;
				
				File fromFolder=new File( fromFile.getParent() );
				lst= fromFolder.lastModified();
				toFolder.setLastModified( lst );//同步时间
				
				// log.debug( toFolder.lastModified() + "mkdir-3--\n"+ fromFolder.lastModified() );
				//System.exit(0);
			}
			
			// 文件处理
			if(toFile.exists()){
				toFile.delete();	// 删除是为了应对名称大小写改变
			}
			
			boolean isNew = toFile.createNewFile();   //包括新建和覆盖，覆盖相当于删除加上新建
			//log.debug("-----------rename"+toFile.getAbsoluteFile().getName() + "\n"+fromFile.getName());
//			if(!isNew && !fromFile.getName().equals( toFile.getName() )){
//				toFile.renameTo( fromFile );
//			}
//			log.debug( org.apache.commons.io.FilenameUtils.getBaseName(toFile.getAbsolutePath() ) );
//			log.debug("-----------rename"+toFile.getName() + "\n"+fromFile.getName());
			
			toFile.renameTo( fromFile );	//强制解决文件名称大小写问题
			toFile.setLastModified( fromFile.lastModified());
			bufferIn=new BufferedInputStream(
						new FileInputStream( fromFile ));
			fout=new FileOutputStream(toFile);

			databytes=new byte[1024];
			
			while((k=bufferIn.read(databytes))!=-1){
				//log.debug ("btyes="+databytes);
				fout.write(databytes,0,k);
				//databytes=new byte[1024];
			}
			bufferIn.close();
			fout.close();
			
			lst= fromFile.lastModified();
			toFile.setLastModified(lst);		//因为被截断，不会精确到秒
		}
		return true;
	}
	
	/**
	 * <p>将中文字符转换为 GB2312，解决中文乱码问题。</p>
     * @author WUZEWEN on 2005-10-17
     * @param s 要转换的字符串
     * @return 转换之后的字符串
     * @throws Exception java.io.UnsupportedEncodingException
     */
    public static  String toGB2312(String s) throws Exception {
        if (s == null || s.length() < 1)
            return  s;
        byte[] temp_b = s.getBytes("ISO-8859-1");
        String sTmpStr = new String(temp_b, "GB2312");
        return sTmpStr;

    }

	public String[] getFilterFileExtensions() {
		return filterFileExtensions;
	}

	public void setFilterFileExtensions(String[] filterFileExtensions) {
		this.filterFileExtensions = filterFileExtensions;
	}

	public String[] getFilterFolders() {
		return filterFolders;
	}

	public void setFilterFolders(String[] filterFolders) {
		this.filterFolders = filterFolders;
	}

	
	/**
	 * <p>根据路径，创建目录。</p>
     * @author WUZEWEN on 2005-10-17
     * @param path 要创建的文件夹的路径字符串，分割符为/
     * @return 如果路径存在或者创建成功，返回true，如果创建失败，返回false。
     * @throws no exception
     * @deprecated 功能与mkdirs 相同，不再使用。
     */
	protected boolean createFolder(String path){
		//path like D:/a/b/c/d/e/
		log.debug ("create path="+path);
		if(path.endsWith("/")){
			path=path.substring(0,path.length()-1);
		}
		if(path.indexOf("/")>0){
			String parentPath = path.substring(0,path.lastIndexOf("/")+1);
			File folder=new File(parentPath);
			if(!folder.exists()){
				createFolder(parentPath);	//如果上级目录不存在，先创建
				//folder=new File(path);
				//folder.mkdirs();	//如果上级目录不存在，创建所有需要的，创建的文件夹不能像文件一样设置时间
			}
			folder=new File(path);
			//folder.mkdir();
		}else{
			//到了盘符级了
			return true;
		}
		return true;
	}
	
}
